package cn.wildfirechat.app.utils;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;






/**
 * Apache HttpClient 工具类
 * 
 * @author xxw
 * @date 2019年8月22日
 */
public class HttpClientTool{

	private static final Logger logger = LoggerFactory.getLogger(HttpClientTool.class);

	/**
	 * GET请求
	 * 
	 * @param url
	 * @param param
	 * @return
	 * @author xxw
	 * @date 2019年8月22日
	 */
	public String httpGet(String url, String jsonParams) {
		//返回值
		String result = "";
		//生成请求流水号（唯一）
		String serialNumber = System.currentTimeMillis()+"";
		logger.debug("★★★★★★★★★ 本次GET请求流水号："+serialNumber+"，请求URL："+url+"，请求参数："+jsonParams);
		// 获得Http客户端
		CloseableHttpClient httpClient = HttpClientBuilder.create().build();
		// 响应模型
		CloseableHttpResponse response = null;
		try {
			// 由于GET请求的参数都是拼装在URL地址后方，所以我们要构建一个URL，带参数
	        URIBuilder uriBuilder = new URIBuilder(url);
	        // 第一种添加参数的形式
//	        uriBuilder.addParameter("name", "root");
//	        uriBuilder.addParameter("password", "123456");
	        // 第二种添加参数的形式
	        List<NameValuePair> list = new LinkedList<>();
	        BasicNameValuePair param1 = new BasicNameValuePair("jsonParams", jsonParams);
	        list.add(param1);
	        uriBuilder.setParameters(list);
	        //设置编码格式
	        uriBuilder.setCharset(Charset.forName("utf-8"));
			// 创建Get请求
			HttpGet httpGet = new HttpGet(uriBuilder.build());
			// 添加请求头信息
			httpGet.addHeader("Content-Type", "application/json;charset=utf8");
			// 配置信息
			RequestConfig requestConfig = RequestConfig.custom()
					// 设置连接超时时间(单位毫秒)
					.setConnectTimeout(5000)
					// 设置请求超时时间(单位毫秒)
					.setConnectionRequestTimeout(5000)
					// socket读写超时时间(单位毫秒)
					.setSocketTimeout(5000)
					// 设置是否允许重定向(默认为true)
					.setRedirectsEnabled(true).build();
 
			// 将上面的配置信息 运用到这个Get请求里
			httpGet.setConfig(requestConfig);

			// 由客户端执行(发送)Get请求
			response = httpClient.execute(httpGet);
			// 从响应模型中获取响应实体
			HttpEntity responseEntity = response.getEntity();
			logger.debug("★★★★★★★★★ 本次GET请求流水："+serialNumber+"， 响应状态为:" + response.getStatusLine());
			if (responseEntity != null) {
				String res = EntityUtils.toString(responseEntity, "utf-8");
				logger.debug("★★★★★★★★★ 本次GET请求流水："+serialNumber+"， 响应内容长度为:" + responseEntity.getContentLength());
				logger.debug("★★★★★★★★★ 本次GET请求流水："+serialNumber+"， 响应内容为:" + res);
				if(200==response.getStatusLine().getStatusCode()){
					result = res;
				}
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
			logger.error("★★★★★★★★★ 本次GET请求流水："+serialNumber+"， Http协议异常：" ,e);
		} catch (ParseException e) {
			e.printStackTrace();
			logger.error("★★★★★★★★★ 本次GET请求流水："+serialNumber+"， 解析异常：" ,e);
		} catch (IOException e) {
			e.printStackTrace();
			logger.error("★★★★★★★★★ 本次GET请求流水："+serialNumber+"， IO异常：" ,e);
		} catch (URISyntaxException e) {
			e.printStackTrace();
			logger.error("★★★★★★★★★ 本次GET请求流水："+serialNumber+"， URI解析异常：" ,e);
		} finally {
			try {
				// 释放资源
				if (null != httpClient) {
					httpClient.close();
				}
				if (null != response) {
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
				logger.error("★★★★★★★★★ 本次GET请求流水："+serialNumber+"， 释放连接出错:", e);
			}
		}
		return result;
	}
	
	/**
	 * POST请求
	 * @param url
	 * @param 对象转JSON字符传输，接收为对象类型
	 * @return
	 * @author xxw
	 * @date 2019年8月29日
	 */
	public static String httpPost(String url, String jsonParams) {
		//返回值
		String result = "";
		//生成请求流水号（唯一）
		String serialNumber = System.currentTimeMillis()+"";
		logger.debug("★★★★★★★★★ 本次POST请求流水号："+serialNumber+"， 请求URL："+url+"， 请求参数："+jsonParams);
		// 获得Http客户端
		CloseableHttpClient httpClient = null;
		if(url.trim().toLowerCase().startsWith("https")){
			httpClient = getIgnoreSslClient();
		}else{
			httpClient = HttpClientBuilder.create().build();
		}
		// 创建Post请求
		HttpPost httpPost = new HttpPost(url);
		StringEntity entity = new StringEntity(jsonParams, "UTF-8");
		// post请求是将参数放在请求体里面传过去的;这里将entity放入post请求体中
		httpPost.setEntity(entity);
		entity.setContentEncoding("UTF-8");   
		entity.setContentType("application/json;charset=utf8");
		httpPost.setHeader("Content-Type", "application/json;charset=utf8");
		// 配置信息
		RequestConfig requestConfig = RequestConfig.custom()
				// 设置连接超时时间(单位毫秒)
				.setConnectTimeout(60000)
				// 设置请求超时时间(单位毫秒)
				.setConnectionRequestTimeout(60000)
				// socket读写超时时间(单位毫秒)
				.setSocketTimeout(60000)
				// 设置是否允许重定向(默认为true)
				.setRedirectsEnabled(true).build();
 
			// 将上面的配置信息 运用到这个Get请求里
		httpPost.setConfig(requestConfig);
		// 响应模型
		CloseableHttpResponse response = null;
		try {
			// 由客户端执行(发送)Post请求
			response = httpClient.execute(httpPost);
			// 从响应模型中获取响应实体
			HttpEntity responseEntity = response.getEntity();
			logger.debug("★★★★★★★★★ 本次POST请求流水："+serialNumber+"， 响应状态为:" + response.getStatusLine());
			if (responseEntity != null) {
				String res = EntityUtils.toString(responseEntity, "utf-8");
				logger.debug("★★★★★★★★★ 本次POST请求流水："+serialNumber+"， 响应内容长度为:" + responseEntity.getContentLength());
				//logger.debug("★★★★★★★★★ 本次POST请求流水："+serialNumber+"， 响应内容为:" + res);
				if(200==response.getStatusLine().getStatusCode()){
					result = res;
				}
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
			logger.error("★★★★★★★★★ 本次POST请求流水："+serialNumber+"， Http协议异常：" ,e);
		} catch (ParseException e) {
			e.printStackTrace();
			logger.error("★★★★★★★★★ 本次POST请求流水："+serialNumber+"， 解析异常：" ,e);
		} catch (IOException e) {
			e.printStackTrace();
			logger.error("★★★★★★★★★ 本次POST请求流水："+serialNumber+"， IO异常：" ,e);
		} finally {
			try {
				// 释放资源
				if (httpClient != null) {
					httpClient.close();
				}
				if (response != null) {
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return result;
	}
	
	/**
	 * 忽略证书
	 * @return
	 * @author xxw
	 * @date 2019年9月2日
	 */
	public static CloseableHttpClient getIgnoreSslClient(){
		RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory>create();
        ConnectionSocketFactory plainSF = new PlainConnectionSocketFactory();
        registryBuilder.register("http", plainSF);
        // 指定信任密钥存储对象和连接套接字工厂
        try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            // 信任任何链接
            TrustStrategy anyTrustStrategy = new TrustStrategy() {
            	//信任所有
            	@Override
            	public boolean isTrusted(X509Certificate[] chain,String authType) throws CertificateException {
            		return true;
            	}
            };
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(trustStore, anyTrustStrategy).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
            //httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
            registryBuilder.register("https", sslsf);
        } catch (KeyStoreException e) {
            throw new RuntimeException(e);
        } catch (KeyManagementException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
		Registry<ConnectionSocketFactory> registry = registryBuilder.build();
		// 设置连接管理器
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);
        return HttpClientBuilder.create().setConnectionManager(connManager).build();
	}
	
	/**
	 * POST请求
	 * @param url
	 * @param MAP键值对传输，接收为普通类型参数
	 * @return
	 * @author xxw
	 * @date 2019年8月29日
	 */
	public static String httpPost(String url, Map<String, Object> map) {
		//返回值
		String result = "";
		//生成请求流水号（唯一）
		String serialNumber = System.currentTimeMillis()+"";
		logger.debug("★★★★★★★★★ 本次POST请求流水号："+serialNumber+"， 请求URL："+url+"， 请求参数："+map.toString());
		// 获得Http客户端
		CloseableHttpClient httpClient = null;
		if(url.trim().toLowerCase().startsWith("https")){
			httpClient = getIgnoreSslClient();
		}else{
			httpClient = HttpClientBuilder.create().build();
		}
		// 将参数放入键值对类NameValuePair中,再放入集合中
		List<NameValuePair> params = new ArrayList<>();
		for(String key : map.keySet()){
			Object str = map.get(key);
			String value = (str!=null && str.toString().trim()!="")?str.toString().trim():"";
			params.add(new BasicNameValuePair(key, value));
		}
		
		// 创建Post请求
		HttpPost httpPost = new HttpPost(url);
		httpPost.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8));
		// 配置信息
		RequestConfig requestConfig = RequestConfig.custom()
				// 设置连接超时时间(单位毫秒)
				.setConnectTimeout(60000)
				// 设置请求超时时间(单位毫秒)
				.setConnectionRequestTimeout(60000)
				// socket读写超时时间(单位毫秒)
				.setSocketTimeout(60000)
				// 设置是否允许重定向(默认为true)
				.setRedirectsEnabled(true).build();
 
			// 将上面的配置信息 运用到这个Get请求里
		httpPost.setConfig(requestConfig);
		// 响应模型
		CloseableHttpResponse response = null;
		try {
			// 由客户端执行(发送)Post请求
			response = httpClient.execute(httpPost);
			// 从响应模型中获取响应实体
			HttpEntity responseEntity = response.getEntity();
			logger.debug("★★★★★★★★★ 本次POST请求流水："+serialNumber+"， 响应状态为:" + response.getStatusLine());
			if (responseEntity != null) {
				String res = EntityUtils.toString(responseEntity, "utf-8");
//				logger.debug("★★★★★★★★★ 本次POST请求流水："+serialNumber+"， 响应内容长度为:" + responseEntity.getContentLength());
//				logger.debug("★★★★★★★★★ 本次POST请求流水："+serialNumber+"， 响应内容为:" + res);
				if(200==response.getStatusLine().getStatusCode()){
					result = res;
				}
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
			logger.error("★★★★★★★★★ 本次POST请求流水："+serialNumber+"， Http协议异常：" ,e);
		} catch (ParseException e) {
			e.printStackTrace();
			logger.error("★★★★★★★★★ 本次POST请求流水："+serialNumber+"， 解析异常：" ,e);
		} catch (IOException e) {
			e.printStackTrace();
			logger.error("★★★★★★★★★ 本次POST请求流水："+serialNumber+"， IO异常：" ,e);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("★★★★★★★★★ 本次POST请求流水："+serialNumber+"异常：" ,e);
		} finally {
			try {
				// 释放资源
				if (httpClient != null) {
					httpClient.close();
				}
				if (response != null) {
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return result;
	}
	
	
	/**
	 * 转化为流
	 * 
	 * @param resp			响应对象
	 * @param out			输出流
	 * @return				返回输出流
	 * @throws HttpProcessException	http处理异常 
	 */
	public OutputStream fmt2Stream(HttpResponse resp, OutputStream out){
		try {
			resp.getEntity().writeTo(out);
			EntityUtils.consume(resp.getEntity());
		} catch (IOException e) {
			e.printStackTrace();
		}
		return out;
	}
	
	
	public static Map<String, Object>  bulidParamsForMemeberHttp(Map<String, String> params){
		Map<String , Object> map=new LinkedHashMap<String, Object>();
		try {
		Iterator<?> iteratorObj = params.entrySet().iterator();
		List<Object> paramList=new ArrayList<Object>();
		while (iteratorObj.hasNext()) {
			@SuppressWarnings("unchecked")
			Entry<String, Object> entry = (Entry<String, Object>) iteratorObj.next();
			map.put(entry.getKey(), entry.getValue());
			paramList.add(entry.getKey() + "=" + entry.getValue());
		}
		//修改会员接口参数规则，解决排序问题！baohui.LU 2015/12/11
		String[] paramsArr = paramList.toArray(new String[]{});
		Arrays.sort(paramsArr);
		StringBuffer stringBuffer = new StringBuffer();
		for(String param:paramsArr){
			stringBuffer.append(param+"&");
		}
		} catch (Exception e) {
//			SystemLogUitls.info("", "", "", CommonService.class,params.toString(), e, LogConstant.DATA_DEAL_CALLBACK, LogConstant.SYSTEM_VITAROLE, "调用会员接口时进行加密时出错", ConfigConstant.member_sys_sign, LogConstant.OTHER_LOG_COMMON);
			e.printStackTrace();
		}
	  return map;	
	}

}
